package cheme.ProcessModel.Interpreter;

import java.util.Iterator;

import cheme.ProcessModel.IModelElement;
import cheme.ProcessModel.ModelEnv;
import cheme.ProcessModel.ProcessModelConstants;

//import cheme.ProcessModel.Interpreter.IRule.RuleResult;
import cheme.ProcessModel.Annotations.Annotation;
import cheme.ProcessModel.Interpreter.IRule.RuleResult;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.AbstractTagComponent;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.IGeneralTagComponent;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.ITagComponent;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.OverallTagComponent;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.TagComponentList;

public abstract class ComponentIteratingRule implements IRule
{
	private IModelElement thisComponent = null;
	protected Interpreter interpreter = null;
	
	protected abstract RuleResult ComponentCheck(IModelElement component);
	protected abstract boolean QtyCheck(float ichildQty);
		
	public RuleResult applyTo(IModelElement object)
	{		
		setComponent(object);
		RuleResult result = null;
		String strmodel = null;
		boolean bStatus = true;
		AbstractTagComponent component = (AbstractTagComponent)object;
		int nChildrenSize = 0;
		setComponent(component);
		
		if(!(object instanceof OverallTagComponent))
		{
			// get the overall component
			OverallTagComponent tmpParent = (OverallTagComponent)((IModelElement)component.getParent().getParent().getChildren().get(0));
			component = (AbstractTagComponent)tmpParent;
			nChildrenSize = component.getParent().getChildren().size();
		}
		else
		{
			strmodel = component.getLabel();
			nChildrenSize = component.getParent().getChildren().size();
		}
		
		// check if this has sub components			
		
			if (nChildrenSize > 1)
			{
				result = ComponentCheck(component); // call with overalltag for the first time
				Iterator<ITagComponent> iterator = (Iterator<ITagComponent>) (component.getParent().getChildren().iterator());
				//reach to Tag Component List
				iterator.next(); 
				// reach to first sub component
				TagComponentList subComponent = (TagComponentList)iterator.next();
				//	 get new iterator for Component List
				Iterator<IGeneralTagComponent> Listiterator = subComponent.getChildren().iterator();
				ITagComponent childComponent = null;
				
				while(Listiterator.hasNext()&& null  != result)// && (result instanceof IRule.Success))
				{				
					childComponent = (ITagComponent)Listiterator.next();
					if(childComponent.isInitial())break;
										
					setComponent(childComponent);			
					
					result = ComponentCheck(childComponent); 
					if(!(result instanceof IRule.Success))
					{
						bStatus = false;						
					}
					
					strmodel = childComponent.getLabel();
					// Set proper Annotation for each Child component
					setAnnotation(result,strmodel);				
					
					
					//result = PostParseRules.tagComponentUnitNotSameAsOverAll.applyTo(childComponent);
					//result =  applyTo(childComponent);
					//setModelError(ruleResult.getSource(), new Annotation(ruleResult.getSource(), ProcessModelConstants.DESC_ERROR, ruleResult.getMessage()));
				}
				// Once all the Annotaions are set, check for Qty consistency.
				// This check should be performed if all the Units are Ok
				if(bStatus)
				{
					float iTotalChildQty = 0;
					boolean childIsUnknown = false;
					//int iTotalChildQty = 0;
					// reset the iterator
					Listiterator = subComponent.getChildren().iterator();
					childComponent = null;
					while(Listiterator.hasNext()&& null  != result)// && (result instanceof IRule.Success))
					{				
						childComponent = (ITagComponent)Listiterator.next();
						String childQty = childComponent.getQuantity();// get Child Quantity
						// This means that next element is not fully specified.
						if((childQty.equals("?")|| childQty.isEmpty()) && !(childComponent.isInitial()))
						{
							childIsUnknown = true;
							continue;
							//break;
						}
						if(!(childQty.isEmpty())&& (!(childQty.equals("?"))))
							iTotalChildQty += Float.valueOf(childQty);									
					}
					//boolean bResult = QtyCheck(iTotalChildQty);
					
					// Set overall Component as main component
					setComponent(component);
					strmodel = component.getLabel();
					
					// if child qty is unknown then do not check for Qty.
					if(!childIsUnknown)
					{
						if(QtyCheck(iTotalChildQty))
						{
							result = new IRule.Success((IModelElement)component);
						}
						else
						{
							result = new IRule.Warning((IModelElement)component, "The sum of the quantities of all individual compounds is not equal to the quantity of overall stream, or 100%.\nMake sure that  the quantities of all individual compounds add up to the quantity of overall stream, or 100%");
						}
					}
					else
					{
						result = new IRule.Success((IModelElement)component);
					}
					
					// set the object to overall tag component so that meesage appears only with the overAll Tag
					object = (IModelElement)component;	
					String strLabel = component.getLabel();
					setAnnotation(result, strLabel);
				}
				// Get interpretor for component with which this funtion is called
				/*interpreter = ModelEnv.getInstanceFor(getComponent()).getInterpreter();
				ModelElementData modelData = interpreter.getModelData(component.getLabel());
				if ( null != modelData)
				{
					if(result instanceof IRule.Success)
					{
						modelData.setErrorAnnotation(null);
					}
					else
					{
						modelData.setErrorAnnotation(new Annotation(object, ProcessModelConstants.DESC_WARNING, result.getMessage()));
					}
				}*/
			}
		
		return result;
	}
	
	public void setComponent(IModelElement component)
	{
		this.thisComponent = component;
	}

	/**
	 * @return the equation
	 */
	public IModelElement  getComponent()
	{
		return thisComponent;
	}
	
	public void setAnnotation(RuleResult result, String strLabel)
	{
		interpreter = ModelEnv.getInstanceFor(getComponent()).getInterpreter();
		ModelElementData modelData = interpreter.getModelData(strLabel);
		
		if ( null != modelData)
		{
			if(result instanceof IRule.Success)
			{
				interpreter.removeEntry(result.getSource());	
				modelData.setErrorAnnotation(null);
			}
			else
			{
				if (null != result){
				String strmsg = interpreter.updateConsoleMap(result);
				// PA commented for non feedback version
				//modelData.setErrorAnnotation(new Annotation(getComponent(), ProcessModelConstants.DESC_WARNING, result.getMessage(),strmsg));
				}
			}
		}
	}
	
}
